<script>
import { FormItem } from 'element-ui'
import normalizeVnode from './normalizeVnode'
export default {
  name: 'Index',
  props: {
    // 透传至Form,用户数据
    model: {
      type: Object,
      default: () => {}
    },
    // formItem的表单配置
    formItems: {
      type: Array,
      default: () => []
    },
    // 纵列展示
    column: {
      type: Number,
      default: null
    }
  },
  methods: {
    // 表单验证
    stairValidate() {
      return new Promise((resolve, reject) => {
        this.$refs.form.validate((valid, errMessage) => {
          if (!valid) {
            // 说明表单验证不通过
            this.$emit('validationError', errMessage)
          }
          const result = !valid
            ? false
            : { formDatas: this.model }
          return resolve(result)
        })
      })
    },
    // 表单数据提交
    formSubmit() {
      return Promise.all([this.stairValidate()]).then(values => {
        // 判断数据是否验证通过
        const whether = values.findIndex(findItem => {
          return findItem === false
        })
        if (whether !== -1) {
          return Promise.resolve(null)
        } else {
          const data = { ...values[0] }
          return Promise.resolve(data)
        }
      })
    },
    // 创建节点FormItems
    createFormItemsVNode(h, configs) {
      const Vnode = configs.map(config => {
        return this.normalizeFormItem(h, config)
      })
      return <div style={{ '--colunm': this.column }} class={ ['form-item-style', !this.column ? 'flex' : ''] }>{Vnode}</div>
    },
    /**
     * @description: 匹配组件，并做处理
     * @param { Object } config 组件信息
     * @return { Vnode } 组件节点
     */
    normalizeFormItem(h, config) {
      /**
      * @param { String } label      文本信息
      * @param { String } type       组件类型
      * @param { String } key        对应后端的字段名称
      * @param { Object } attrs      FormItem组件属性
      * @param { Object } inner      组件对应element的属性
      * @param { String } ext        select等组件需要的opions字段
      * @param { Object } vIf        字段需展示的条件
      * @param { Boolean } mutable   是否可编辑
      * @param { String } validator  校验规则对应已有的key
      * @param { Vnode } slot        自定义内容
      * @param { Vnode } slotLabel   自定义标题
      */
      const { label, type, key, inner, attrs, vIf, mutable = true, validator, slot, slotLabel } = config
      let rulesKey = key

      // 对数据做处理
      let value = ''
      if (typeof key === 'string') {
        value = this.model[key]
      } else if (Array.isArray(key)) {
        value = []
        key.forEach(e => {
          value.push(this.model[e])
        })
        rulesKey = key[0]
      } else {
        if (label !== '') {
          console.error(label + '不支持key的类型')
          return
        }
      }
      let vnode
      if (slot) {
        vnode = slot(this.model)
      } else {
        // 规范组件节点
        vnode = normalizeVnode(h, config, this.model, value, this)
      }
      const labelFilter = !mutable && label && label !== '' && !label.lastIndexOf(':', 0) >= 0 && !label.lastIndexOf('：', 0) >= 0 ? label + '：' : label
      // 验证是否展示items
      if (!this.verifyIsShowItems(vIf)) return
      // 增加验证规则
      const curAttrs = validator ? this.setValidator(label, type, attrs, validator, inner) : attrs
      return (
        <FormItem
          prop={rulesKey}
          key={rulesKey}
          {...curAttrs}
          label={labelFilter}
          scopedSlots={{
            label: props => {
              return slotLabel ? <div style='flex: 1;'>{slotLabel()}</div> : null
            }
          }}
        >
          {[vnode]}
        </FormItem>
      )
    },
    // 验证是否展示items
    verifyIsShowItems(obj) {
      if (typeof obj === 'boolean') return obj
      if (!obj || obj.length === 0) return true
      const arr = this.formItems.filter(e => obj.find(vIf => vIf.key === e.key))
      let isBol = true
      for (const item of arr) {
        const vIfItem = obj.find(e => e.key === item.key)
        // 判断联动的表单值，满足则显示
        if (Array.isArray(vIfItem.value)) {
          if (Array.isArray(this.model[item.key])) {
            if (!(this.model[item.key].length === vIfItem.value.length && this.model[item.key].filter(t => !vIfItem.value.includes(t)))) isBol = false
          } else {
            if (!vIfItem.value.includes(this.model[item.key])) {
              isBol = false
            }
          }
        } else {
          if (this.model[item.key] !== vIfItem.value) isBol = false
        }
      }
      return isBol
    },
    // 增加验证规则
    setValidator(label, type, attrs, validator, inner) {
      let rules = {}
      const placeholder = inner?.props?.placeholder ? inner.props.placeholder : `请${['select'].includes(type) ? '选择' : '输入'}${label}`
      switch (validator) {
        // 手机号验证
        case 'phone': {
          rules = [
            { required: true, message: placeholder, trigger: 'change' },
            { pattern: /^(13[0-9]|14[01456879]|15[0-3,5-9]|16[2567]|17[0-8]|18[0-9]|19[0-3,5-9])\d{8}$/, message: `请输入正确格式的${placeholder.replace('请输入', '')}`, trigger: 'blur' }
          ]
          break
        }
        default: {
          process.env.NODE_ENV === 'development' && console.error(`提醒：无validator：${validator}对应的校验规则`)
          return undefined
        }
      }
      return {
        ...attrs,
        props: {
          rules
        }
      }
    }
  },
  render(h) {
    const vnodes = this.createFormItemsVNode(h, this.formItems)
    const attrs = this.$attrs
    return (
      <elForm class='config-form' props={{ ...attrs, model: this.model }} ref='form'>
        {vnodes}
      </elForm>
    )
  }
}
</script>
<style scoped lang="less">
  .config-form{
    padding-bottom: 10px;
    &.el-form--inline{
      /deep/.el-form-item{
        display: flex;
        .el-form-item__content{
          flex: 1;
        }
      }
    }
    .form-item-style{
      display: grid;
      grid-template-columns: repeat(var(--colunm), 1fr);
      &.flex{
        display: flex;
        flex-wrap: wrap;
        .el-form-item{
          // min-width: 275px;
          display: flex;
          /deep/ .el-form-item__label{
            white-space: nowrap;
          }
          .el-date-editor--monthrange{
            width: 250px !important;
          }
          .el-date-editor--daterange{
            width: 280px !important;
          }
          .el-date-editor--datetimerange{
            width: 350px !important;
          }
        }
      }
      .tit{
        margin: 10px 10px 10px 0;
        padding: 0 0 8px 10px;
        border-bottom:1px solid #dfdfdf;
        grid-column: 1 / span var(--colunm);
      }
      .el-form-item{
        margin: 10px;
        /deep/.el-input__inner[type=number]{
          -moz-appearance: textfield;
          &::-webkit-inner-spin-button {
            -webkit-appearance: none !important;
          }
        }
        .el-date-editor,
        .el-select{
          width: 100%;
        }
      }
    }
    &.el-form--label-top{
    .form-item-style {
      /deep/ .el-form-item{
        margin: 0 0 10px;
        .el-form-item__label{
          display: flex;
          width: 100%;
          padding: 0;
        }
      }
    }
  }
  }
</style>
